package com.leyou.auth.service;

import com.leyou.auth.config.JwtProperties;
import com.leyou.auth.entity.ApplicationInfo;
import com.leyou.auth.mapper.ApplicationInfoMapper;
import com.leyou.client.UserClient;
import com.leyou.common.auth.entity.AppInfo;
import com.leyou.common.auth.entity.Payload;
import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.CookieUtils;
import com.leyou.dto.UserDTO;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Eric
 * @version v1.0
 * @package com.leyou.auth.service
 * @date 2019/7/7 19:20
 * @description:
 **/
@Service
public class AuthService {

    @Autowired
    private JwtProperties prop;

    @Autowired
    private UserClient userClient;

    @Autowired
    private StringRedisTemplate redisTemplate;


    public void login(String username, String password, HttpServletResponse response) {

        try {
            //校验用户信息是否正确
            UserDTO user = userClient.query(username, password);
            if (user == null) {
                throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
            }

            // 生成userInfo, 没写权限功能，暂时都用guest
            UserInfo userInfo = new UserInfo(user.getId(), user.getUsername(), "GUEST");

            //生成Token
            String token = JwtUtils.generateTokenExpireInMinutes(userInfo, prop.getPrivateKey(), prop.getUser().getExpire());

            //将token储存在cookie中
            CookieUtils.newCookieBuilder()
                    .response(response)
                    .domain(prop.getUser().getCookieDomain())
                    .httpOnly(true)
                    .name(prop.getUser().getCookieName())
                    .value(token)
                    .build();
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }

    }


    public UserInfo verityUser(HttpServletRequest request, HttpServletResponse response) {
        try {
            //获取请求头的cookie中的Token
            String token = CookieUtils.getCookieValue(request, prop.getUser().getCookieName());

            //解析token
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), UserInfo.class);

            //获取jwtId
            String id = payload.getId();
            Boolean boo = redisTemplate.hasKey(id);
            if(id!=null&&boo){
                throw new LyException(ExceptionEnum.UNAUTHORIZED);
            }

            //获取过期时间
            Date expiration = payload.getExpiration();

            //获取刷新时间
            DateTime refreshTime = new DateTime(expiration.getTime()).minusMinutes(prop.getUser().getMinRefreshInterval());
            if (refreshTime.isBefore(System.currentTimeMillis())){

                //重新生成Token
                token=JwtUtils.generateTokenExpireInMinutes(payload.getUserInfo(),prop.getPrivateKey(),prop.getUser().getExpire());

                //写入到cookie中
                CookieUtils.newCookieBuilder()
                        .response(response)
                        .value(token)
                        .name(prop.getUser().getCookieName())
                        .httpOnly(true)
                        .domain(prop.getUser().getCookieDomain())
                        .build();
            }


            return payload.getUserInfo();
        } catch (Exception e) {

            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }

    }


    public void loginOut(HttpServletRequest request, HttpServletResponse response) {

        //获取Token
        String token = CookieUtils.getCookieValue(request, prop.getUser().getCookieName());

        //解析Token
        Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), UserInfo.class);

        //获取JWT的ID
        String jwtId = payload.getId();
        //获取token过期剩余时间
        long time = payload.getExpiration().getTime() - System.currentTimeMillis();
        //将JWT的ID写入Redis
        if (time>5000){
            redisTemplate.opsForValue().set(jwtId,"1",time, TimeUnit.MILLISECONDS);
        }

        //删除Cookie
       CookieUtils.deleteCookie(prop.getUser().getCookieName(),prop.getUser().getCookieDomain(),response);
    }

    @Autowired
    private ApplicationInfoMapper applicationInfoMapper;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    public String authorization(Long id, String secret) {

        //根据Id查询，判断服务是否存在
        ApplicationInfo app = applicationInfoMapper.selectByPrimaryKey(id);

        if (app==null){
            // id不存在，抛出异常
            throw new LyException(ExceptionEnum.INVALID_SERVER_ID_SECRET);
        }

        //判断密码是否正确
        if (!passwordEncoder.matches(secret,app.getSecret())){
            // 密码不存在，抛出异常
            throw new LyException(ExceptionEnum.INVALID_SERVER_ID_SECRET);
        }


        //查询服务目标服务的id
        List<Long> targetIdList = applicationInfoMapper.selectTargetIdList(app.getId());

        //生成载荷封装对象
        AppInfo appInfo = new AppInfo();
        appInfo.setId(id);
        appInfo.setServiceName(app.getServiceName());
        appInfo.setTargetList(targetIdList);

        //生成token
        return JwtUtils.generateTokenExpireInMinutes(appInfo, prop.getPrivateKey(), prop.getUser().getExpire());

    }
}
